/*******************************************************************************
 * This header file contains all the definition of SBASIC.
 *
 * Types, functions, expressions, statement and so on.
 *
 * @author LoveLonelyTime
 * @version 1.1
 * @date 2021-2021
 * @copyright GNU Public License.
 ******************************************************************************/

#ifndef LANGUAGE_H_INCLUDED
#define LANGUAGE_H_INCLUDED

#include <string>
#include <map>
#include <vector>

// use double
#define SBASIC_DECIMAL_TYPE_DOUBLE
#define VERSION 1.1
namespace SBASIC
{
    /**
     * Type definition for line_number.
     * To indicate the line number in the source code.
     */
    typedef unsigned int line_number;

    /**
     * Enum TOKEN.
     * Enumerate all types of TOKEN.
     */
    enum class TOKEN
    {
        DECIMAL_TOKEN,    /**< The decimal TOKEN. */
        IDENTIFIER_TOKEN, /**< The identifier TOKEN. */
        NEWLINE_TOKEN,    /**< The new_line TOKEN. */
        STRING_TOKEN,     /**< The string TOKEN. */
        KEYWORD_TOKEN,    /**< The keyword TOKEN. */
        EOF_TOKEN,        /**< The eof TOKEN. */
        OPERATOR_TOKEN,   /**< The operator TOKEN. */
        DELIMITER_TOKEN   /**< The delimiter TOKEN. */
    };

    /**
     * Enum KEYWORD.
     * Enumerate all available keywords in SBASIC.
     */
    enum class KEYWORD
    {
        INPUT, /**< The INPUT KEYWORD. */
        PRINT, /**< The PRINT KEYWORD. */
        END,   /**< The END KEYWORD. */
        IF,    /**< The IF KEYWORD. */
        THEN,  /**< The THEN KEYWORD. */
        ELSE,  /**< The ELSE KEYWORD. */
        DO,    /**< The DO KEYWORD. */
        LOOP,  /**< The LOOP KEYWORD. */
        UNTIL, /**< The UNTIL KEYWORD. */
        WHILE, /**< The WHILE KEYWORD. */
        WEND   /**< The WEND KEYWORD. */
    };

    /**
     * Enum DELIMITER.
     * Enumerate all delimiters.
     */
    enum class DELIMITER
    {
        NEW_LINE,         /**< The '\n' DELIMITER. */
        SEMICOLON,        /**< The ';' DELIMITER. */
        COMMA,            /**< The ',' DELIMITER. */
        LEFT_PARENTHESIS, /**< The '(' DELIMITER. */
        RIGHT_PARENTHESIS /**< The ')' DELIMITER. */
    };

    /**
     * Enum OPERATOR.
     * Enumerate all available operators in SBASIC.
     */
    enum class OPERATOR
    {
        PLUS,                  /**< The '+' OPERATOR. */
        SUBSTRACT,             /**< The '-' OPERATOR. */
        MULTIPLY,              /**< The '*' OPERATOR. */
        DIVIDE,                /**< The '/' OPERATOR. */
        DIVIDE_EXACTLY,        /**< The '\' OPERATOR. */
        POWER,                 /**< The '^' OPERATOR. */
        MOD,                   /**< The '%' DELIMITER. */
        EQUAL,                 /**< The '==' DELIMITER. */
        GREATER_THEN,          /**< The '>' DELIMITER. */
        LESS_THEN,             /**< The '<' DELIMITER. */
        NOT_EQUAL,             /**< The '<>' DELIMITER. */
        GREATER_THEN_OR_EQUAL, /**< The '<=' DELIMITER. */
        LESS_THEN_OR_EQUAL,    /**< The '>=' DELIMITER. */
        AND,                   /**< The 'AND' DELIMITER. */
        OR,                    /**< The 'OR' DELIMITER. */
        NOT                    /**< The 'NOT' DELIMITER. */
    };

//! Specifies the C++ type corresponding to the numeric type used
/**
 * SBASIC decimal type.
 */
#if defined SBASIC_DECIMAL_TYPE_LONG_DOUBLE
    typedef long double sbasic_decimal_type;
#elif defined SBASIC_DECIMAL_TYPE_FLOAT
    typedef float sbasic_decimal_type;
#elif defined SBASIC_DECIMAL_TYPE_DOUBLE
    typedef double sbasic_decimal_type;
#endif

    /**
     * SBASIC builtin function pointer.
     */
    typedef sbasic_decimal_type (*sbasic_function_pointer)(const std::vector<sbasic_decimal_type> &args);

    /**
     * The boolean type in SBASIC.
     * True.
     */
    const sbasic_decimal_type sbasic_true = 1;

    /**
     * The boolean type in SBASIC.
     * False.
     */
    const sbasic_decimal_type sbasic_false = 0;

    /**
     * Convert function.
     * string to decimal.
     * @param[in] str string.
     * @return Decimal type.
     */
    sbasic_decimal_type string_to_decimal(const std::string &str);

    /**
     * Convert function.
     * string to keyword.
     * @param[in] str string.
     * @return Keyword type.
     */
    KEYWORD string_to_keyword(const std::string &str);

    /**
     * Convert function.
     * string to letter operator.
     * @param[in] str string.
     * @return Operator type.
     */
    OPERATOR string_to_letter_operator(const std::string &str);

    /**
     * Assertion function.
     * Is a keyword.
     * @param[in] str string.
     * @return The result of assertion.
     */
    bool is_keyword(const std::string &str);

    /**
     * Assertion function.
     * Is a letter operator.
     * @param[in] str string.
     * @return The result of assertion.
     */
    bool is_letter_operator(const std::string &str);

    /**
     * Assertion function.
     * Is a prefix operator.
     * @param[in] c character.
     * @return The result of assertion.
     */
    bool is_prefix_operator(char c);

    /**
     * Assertion function.
     * Is a delimiter.
     * @param[in] c character.
     * @return The result of assertion.
     */
    bool is_delimiter(char c);

    /**
     * The VariableTable class.
     * As a symbol table in the interpreter.
     * The internal implementation uses red black tree.
     * The external is a linked list structure.
     */
    class VariableTable
    {
    private:
        /**
         * R&B tree.
         */
        std::map<std::string, sbasic_decimal_type> m_variables;

        /**
         * The previous pointer.
         */
        VariableTable *m_previous_variable_table_ptr;

    public:
        /**
         * Create a VariableTable node.
         * @param[in] previous_variable_table_ptr The previous pointer.
         */
        VariableTable(VariableTable *previous_variable_table_ptr) : m_previous_variable_table_ptr(previous_variable_table_ptr) {}

        /**
         * Get the variable value.
         * Its time complexity is O(logn).
         * @param[in] variable_name The variable name.
         * @return The variable value.
         */
        sbasic_decimal_type get_variable(const std::string &variable_name);

        /**
         * Put a variable.
         * Its time complexity is O(logn).
         * @param[in] variable_name The variable name.
         * @param[in] sdt The variable value.
         */
        void assign_variable(const std::string &var_name, sbasic_decimal_type sdt);
    };

    /**
     * The VariableTable class.
     * As a common builtin function table.
     * The internal implementation uses red black tree.
     */
    class FunctionTable
    {
    private:
        /**
         * R&B tree.
         */
        std::map<std::string, sbasic_function_pointer> m_functions;

    public:
        /**
         * Put the function pointer.
         * Its time complexity is O(logn).
         * @param[in] function_name The function name.
         * @param[in] fp The function pointer.
         */
        void put_function(const std::string &function_name, sbasic_function_pointer fp)
        {
            m_functions[function_name] = fp;
        }

        /**
         * Get the function pointer.
         * Its time complexity is O(logn).
         * @param[in] function_name The function name.
         * @return The function pointer.
         */
        sbasic_function_pointer get_function(const std::string &function_name);
    };

    /**
     * The Expression class.
     * Represents a computable expression in SBASIC.
     */
    class Expression
    {
    public:
        /**
         * Compute this Expression.
         * This operation needs the context.
         * @param[in] function_table The function table.
         * @param[in] variable_table The variable table.
         */
        virtual sbasic_decimal_type compute(FunctionTable &function_table, VariableTable *variable_table) = 0;

        virtual ~Expression() {}
    };

    class TailExpression
    {
    private:
        OPERATOR m_operator;
        Expression *m_expression;

    public:
        OPERATOR get_operator() const
        {
            return m_operator;
        }

        Expression *get_expression() const
        {
            return m_expression;
        }

        void set_operator(OPERATOR op)
        {
            m_operator = op;
        }

        void set_expression(Expression *expression)
        {
            m_expression = expression;
        }
    };

    /**
     * The UnaryExpression class.
     * Unary-Expression.
     */
    class UnaryExpression : public Expression, public TailExpression
    {
        sbasic_decimal_type compute(FunctionTable &function_table, VariableTable *variable_table) override;
    };

    /**
     * The VariableExpression class.
     * A Variable usage.
     */
    class VariableExpression : public Expression
    {
    private:
        std::string m_var_name;
        line_number m_line_number;

    public:
        std::string get_variable_name() const
        {
            return m_var_name;
        }

        line_number get_line_number() const
        {
            return m_line_number;
        }

        void set_variable_name(const std::string &variable_name)
        {
            m_var_name = variable_name;
        }

        void set_line_number(line_number ln)
        {
            m_line_number = ln;
        }

        sbasic_decimal_type compute(FunctionTable &function_table, VariableTable *variable_table) override;
    };

    /**
     * The BinaryExpression class.
     * Binary-Expression.
     * Left-Expression operator Right-Expression.
     */
    class BinaryExpression : public Expression
    {
    private:
        OPERATOR m_operator;
        Expression *m_left_expression;
        Expression *m_right_expression;

    public:
        OPERATOR get_operator() const
        {
            return m_operator;
        }

        Expression *get_left_expression() const
        {
            return m_left_expression;
        }

        Expression *get_right_expression() const
        {
            return m_right_expression;
        }

        void set_operator(OPERATOR op)
        {
            m_operator = op;
        }

        void set_left_expression(Expression *expression)
        {
            m_left_expression = expression;
        }

        void set_right_expression(Expression *expression)
        {
            m_right_expression = expression;
        }

        sbasic_decimal_type compute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~BinaryExpression()
        {
            delete m_left_expression;
            delete m_right_expression;
        }
    };

    /**
     * The CallExpression class.
     * Call a function.
     */
    class CallExpression : public Expression
    {
    private:
        std::string m_function_name;
        std::vector<Expression *> m_expressions;
        line_number m_line_number;

    public:
        void add_expression(Expression *expression)
        {
            m_expressions.push_back(expression);
        }

        line_number get_line_number() const
        {
            return m_line_number;
        }

        std::string get_function_name() const
        {
            return m_function_name;
        }

        void set_function_name(const std::string &function_name)
        {
            m_function_name = function_name;
        }

        void set_line_number(line_number ln)
        {
            m_line_number = ln;
        }

        sbasic_decimal_type compute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~CallExpression()
        {
            for (auto it = m_expressions.begin(); it != m_expressions.end(); ++it)
            {
                delete (*it);
            }
        }
    };

    /**
     * The DecimalExpression class.
     * It's decimal.
     */
    class DecimalExpression : public Expression
    {
    private:
        sbasic_decimal_type m_sdt;

    public:
        sbasic_decimal_type get_decimal() const
        {
            return m_sdt;
        }

        void set_decimal(sbasic_decimal_type decimal)
        {
            m_sdt = decimal;
        }

        sbasic_decimal_type compute(FunctionTable &function_table, VariableTable *variable_table) override
        {
            return m_sdt;
        }
    };

    /**
     * The Stmt class.
     * Represents a executable statement in SBASIC.
     */
    class Stmt
    {
    public:
        /**
         * Cxecute this Statement.
         * This operation needs the context.
         * @param[in] function_table The function table.
         * @param[in] variable_table The variable table.
         */
        virtual void execute(FunctionTable &function_table, VariableTable *variable_table) = 0;

        virtual ~Stmt() {}
    };

    /**
     * The PrintStmt class.
     * To print user's message to console.
     */
    class PrintStmt : public Stmt
    {
    private:
        std::string m_prompt;
        bool has_prompt;
        std::vector<Expression *> m_expressions;

    public:
        std::string get_prompt() const
        {
            return m_prompt;
        }

        void set_prompt(const std::string &prompt)
        {
            m_prompt = prompt;
            has_prompt = true;
        }

        void add_expression(Expression *expression)
        {
            m_expressions.push_back(expression);
        }

        void execute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~PrintStmt()
        {
            for (auto it = m_expressions.begin(); it != m_expressions.end(); ++it)
            {
                delete (*it);
            }
        }
    };

    /**
     * The InputStmt class.
     * To input user's keyboard from console.
     */
    class InputStmt : public Stmt
    {
    private:
        std::string m_prompt;
        bool has_prompt;
        std::vector<VariableExpression *> m_expressions;

    public:
        std::string get_prompt() const
        {
            return m_prompt;
        }

        void set_prompt(const std::string &prompt)
        {
            m_prompt = prompt;
            has_prompt = true;
        }

        void add_expression(VariableExpression *expression)
        {
            m_expressions.push_back(expression);
        }

        void execute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~InputStmt()
        {
            for (auto it = m_expressions.begin(); it != m_expressions.end(); ++it)
            {
                delete (*it);
            }
        }
    };

    /**
     * The AssignmentStmt class.
     * To assign a value to variable.
     */
    class AssignmentStmt : public Stmt
    {
    private:
        VariableExpression *m_variable_expression;
        Expression *m_expression;

    public:
        VariableExpression *get_variable_expression() const
        {
            return m_variable_expression;
        }

        void set_variable_expression(VariableExpression *variable_expression)
        {
            m_variable_expression = variable_expression;
        }

        Expression *get_expression() const
        {
            return m_expression;
        }

        void set_expression(Expression *expression)
        {
            m_expression = expression;
        }

        void execute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~AssignmentStmt()
        {
            delete m_expression;
            delete m_variable_expression;
        }
    };

    /**
     * The DOIteratorStmt class.
     * DO-statement.
     */
    class DOIteratorStmt : public Stmt
    {
    private:
        Expression *m_condition;
        std::vector<Stmt *> m_stmts;

    public:
        Expression *get_condition() const
        {
            return m_condition;
        }

        void set_condition(Expression *expression)
        {
            m_condition = expression;
        }

        void add_stmt(Stmt *stmt)
        {
            m_stmts.push_back(stmt);
        }
        void execute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~DOIteratorStmt()
        {
            delete m_condition;
            for (auto it = m_stmts.begin(); it != m_stmts.end(); ++it)
            {
                delete (*it);
            }
        }
    };

    /**
     * The SelectionStmt class.
     * IF-statement.
     */
    class SelectionStmt : public Stmt
    {
    private:
        Expression *m_condition;
        std::vector<Stmt *> m_true_stmts;
        std::vector<Stmt *> m_false_stmts;

    public:
        Expression *get_condition() const
        {
            return m_condition;
        }

        void set_condition(Expression *expression)
        {
            m_condition = expression;
        }

        void add_true_stmt(Stmt *stmt)
        {
            m_true_stmts.push_back(stmt);
        }

        void add_false_stmt(Stmt *stmt)
        {
            m_false_stmts.push_back(stmt);
        }

        void execute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~SelectionStmt()
        {
            delete m_condition;
            for (auto it = m_true_stmts.begin(); it != m_true_stmts.end(); ++it)
            {
                delete (*it);
            }
            for (auto it = m_false_stmts.begin(); it != m_false_stmts.end(); ++it)
            {
                delete (*it);
            }
        }
    };

    /**
     * The WHILEIteratorStmt class.
     * WHILE-statement.
     */
    class WHILEIteratorStmt : public Stmt
    {
    private:
        Expression *m_condition;
        std::vector<Stmt *> m_stmts;

    public:
        Expression *get_condition() const
        {
            return m_condition;
        }

        void set_condition(Expression *expression)
        {
            m_condition = expression;
        }

        void add_stmt(Stmt *stmt)
        {
            m_stmts.push_back(stmt);
        }

        void execute(FunctionTable &function_table, VariableTable *variable_table) override;

        ~WHILEIteratorStmt()
        {
            delete m_condition;
            for (auto it = m_stmts.begin(); it != m_stmts.end(); ++it)
            {
                delete (*it);
            }
        }
    };

    /**
     * The Program class.
     * Here, the class represents an SBASIC executable file or an SBASIC fragment.
     */
    class Program
    {
    private:
        std::vector<Stmt *> m_stmts;

    public:
        void add_stmt(Stmt *stmt)
        {
            m_stmts.push_back(stmt);
        }

        /**
         * Running the program.
         * @param[in] function_table The function table.
         * @param[in] variable_table The variable table.
         */
        void run(FunctionTable &function_table, VariableTable *variable_table)
        {
            for (auto it = m_stmts.begin(); it != m_stmts.end(); ++it)
            {
                (**it).execute(function_table, variable_table);
            }
        }

        ~Program()
        {
            for (auto it = m_stmts.begin(); it != m_stmts.end(); ++it)
            {
                delete (*it);
            }
        }
    };
}

#endif // LANGUAGE_H_INCLUDED
